package com.ruoyi.web.system.service.impl;

import com.ruoyi.framework.enums.UserStatus;
import com.ruoyi.framework.exception.user.UserNotExistsException;
import com.ruoyi.framework.exception.user.UserPasswordNotMatchException;
import com.ruoyi.framework.security.SecurityUtils;
import com.ruoyi.framework.utils.ServletUtils;
import eu.bitwalker.useragentutils.UserAgent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.ruoyi.framework.constant.Constants;
import com.ruoyi.framework.constant.UserConstants;
import com.ruoyi.framework.exception.ServiceException;
import com.ruoyi.framework.utils.DateUtils;
import com.ruoyi.framework.utils.StringUtils;
import com.ruoyi.framework.utils.ip.IpUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.web.system.domain.LoginUser;
import com.ruoyi.web.system.domain.SysUser;
import com.ruoyi.web.system.service.ISysUserService;


/**
 * 登录校验方法
 *
 * @author ruoyi
 */
@Component
public class SysLoginService {
    private static final Logger log = LoggerFactory.getLogger(SysLoginService.class);

    @Autowired
    private SysPermissionService permissionService;

    @Autowired
    private ISysUserService userService;


    @Value(value = "${user.password.maxRetryCount}")
    private int maxRetryCount;

    @Value(value = "${user.password.lockTime}")
    private int lockTime;

    /**
     * 登录验证
     *
     * @param username 用户名
     * @param password 密码
     * @return 结果
     */
    public LoginUser login(String username, String password) {
        // 登录前置校验
        loginPreCheck(username, password);

        //检查用户名是否存在及异常状态
        SysUser user = userService.selectUserByUserName(username);
        if (StringUtils.isNull(user)) {
            log.info("登录用户：{} 不存在.", username);
            throw new ServiceException("用户不存在/密码错误");
        } else if (UserStatus.DELETED.getCode().equals(user.getDelFlag())) {
            log.info("登录用户：{} 已被删除.", username);
            throw new ServiceException("对不起，您的账号已被删除");
        } else if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
            log.info("登录用户：{} 已被停用.", username);
            throw new ServiceException("用户已封禁，请联系管理员");
        }

        log.info("===========开始校验密码：" + user.toString());
        //校验密码
        try {
            validate(user, username, password);
        } catch (Exception e) {
            log.info("===========登录异常：" + e.getMessage());
            if (e instanceof UserPasswordNotMatchException) {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户不存在/密码错误"));
                throw new UserPasswordNotMatchException();
            } else {
                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
                throw new ServiceException(e.getMessage());
            }
        } finally {
            //？
//            AuthenticationContextHolder.clearContext();
        }
        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, "登录成功"));
        log.info("===========登录成功：" + user.toString());
        //
        LoginUser loginUser = new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
        loginUser.setOs(userAgent.getOperatingSystem().getName());
        loginUser.setBrowser(userAgent.getBrowser().getName());
        loginUser.setIpaddr(IpUtils.getIpAddr());
        loginUser.setLoginTime(System.currentTimeMillis());
        //更新数据库登录ip时间
        recordLoginInfo(loginUser);
        // 生成token
        return loginUser;
    }

    public void validate(SysUser user, String username, String password) {
        //校验密码是否一致
        log.info("===========validate ：开始校验密码=");
        if (!matches(password, user.getPassword())) {
            log.info("===========validate ：密码错误=");
            throw new UserPasswordNotMatchException();
        }
        //校验密码通过
        else {
            log.info("===========validate ：校验密码通过=");
        }
        log.info("===========validate ：全部完成=");
    }

    public boolean matches(String rawPassword, String encodedPassword) {
        return SecurityUtils.matchesPassword(rawPassword, encodedPassword);
    }


    /**
     * 登录前置校验
     *
     * @param username 用户名
     * @param password 用户密码
     */
    public void loginPreCheck(String username, String password) {
        // 用户名或密码为空 错误
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "* 必须填写"));
            throw new UserNotExistsException();
        }
        // 密码如果不在指定范围内 错误
        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH || password.length() > UserConstants.PASSWORD_MAX_LENGTH) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户不存在/密码错误"));
            throw new UserPasswordNotMatchException();
        }
        // 用户名不在指定范围内 错误
        if (username.length() < UserConstants.USERNAME_MIN_LENGTH || username.length() > UserConstants.USERNAME_MAX_LENGTH) {
            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, "用户不存在/密码错误"));
            throw new UserPasswordNotMatchException();
        }
    }

    /**
     * 记录登录信息
     */
    public void recordLoginInfo(LoginUser loginUser) {
        SysUser sysUser = new SysUser();
        sysUser.setUserId(loginUser.getUserId());
        sysUser.setLoginIp(IpUtils.getIpAddr());
        sysUser.setLoginDate(DateUtils.getNowDate());
        userService.updateUserProfile(sysUser);
    }
}
